/*
 *
 * Copyright (c) 2010 Marco Aurelio Zoqui (http://www.zoqui.com)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Version 1.02
 * $LastChangedDate: 2010-06-30 17:40:00 +0300$
 * $("input").mathparser({});
 */
 
(function($){
	
	function MathParser() {	};
	jQuery.extend(MathParser.prototype,{
		scope: "0123456789.+-*/^%~(, )",
		
		setup: function(target, options) {
			var inst  = {
				enabled:true
			};
			if(options) {
				jQuery.extend(inst, options);
			};
			if (jQuery.data(target, 'mathparser')){
				// just update options
				jQuery.data(target, 'mathparser',inst);
			}
			else{
				// update options and start listening....
				jQuery.data(target, 'mathparser',inst);
				var self = this;//keep context
				if (window.opera) {
					jQuery(target).keydown(function(ev) { self.onKeyPress(ev); });
				}
				else {
					jQuery(target).keypress(function(ev) { self.onKeyPress(ev); });
				}
			}
		},		
					
		parse:function(vlr){
			try{
				if (vlr.length>0){							
					for(var i=0;i<vlr.length;i++){
						if(this.scope.indexOf(vlr.charAt(i))<0)
							return null;
					};
					return vlr;
				}
			}
			catch(err){return null;}
		},
		
		isAllowed:function(e,kc){
			// Control keys: ^A, ^X, ^C, ^Z, ^V
			if((window.opera&&e.ctrlKey)&&(kc in {65:1,88:1,67:1,90:1,86:1})) return true;
			if((!window.opera&&e.ctrlKey)&&(kc in {97:1,120:1,99:1,122:1,118:1})) return true;
			if(kc in{8:1,9:1,13:1,35:1,36:1,37:1,39:1,46:1}) return true;			
			return(this.scope.indexOf(String.fromCharCode(kc))>=0);
			return true;
		},
		
		onKeyPress: function(ev){
			var options = jQuery.data(ev.currentTarget, 'mathparser');
			if (!options.enabled)
				return;
			var kc = ev.charCode ? ev.charCode : ev.keyCode ? ev.keyCode : 0;
			try{
				if (kc in {13:1,9:1,61:1}){
					var el = ev.currentTarget;
					var ret = this.parse(el.value);
					if (ret){
						var vlr = eval('('+ret+')').toString();
						if (vlr!=ret){
							if (kc!=9){
								ev.preventDefault();
								ev.stopPropagation();
							}
							el.value=vlr;
						}
					}
				}
				else{
					if (!this.isAllowed(ev,kc)){
						ev.preventDefault();
						ev.stopPropagation();
					}
				}
				return;
			}
			catch (err) {return;}
		}
		
	});
	
	jQuery.fn.mathparser = function(options) {
		if ((this[0].nodeName.toLowerCase() != 'input')){
			var msg="Target element must be an input";
			if(window.console) {
				console.debug(msg);
			}
			else {
				alert(msg);
			}
			return this;
		}	
		return this.each(function () {
			jQuery.mathparser.setup(this, options);
		});
	};
	
	jQuery.mathparser = new MathParser(); // singleton instance
	
}(jQuery));

